{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DweYe9FcbMK_"
      },
      "source": [
        "##### Copyright 2018 The TensorFlow Authors.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "AVV2e0XKbJeX"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sUtoed20cRJJ"
      },
      "source": [
        "# Memuat Teks"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1ap_W4aQcgNT"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://www.tensorflow.org/tutorials/load_data/text\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />Lihat di TensorFlow.org</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/id/tutorials/load_data/text.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Jalankan di Google Colab</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/id/tutorials/load_data/text.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />Lihat source di GitHub</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/id/tutorials/load_data/text.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\" />Unduh notebook</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NWeQAo0Ec_BL"
      },
      "source": [
        "Tutorial ini menyediakan sebuah contoh cara penggunaan `tf.data.TextLineDataset` untuk memuat file-file teks. `TextLineDataset` didesain untuk membuat sebuah dataset dari file teks, dimana setiap contoh adalah baris dari teks tersebut. Hal ini bermanfaat untuk data teks yang line-based (contohnya, puisi dan log error).\n",
        "\n",
        "Dalam tutorial ini, kita akan menggunakan tiga translasi Inggris yang berbeda dari pekerjaan yang sama yaitu, Homer's Illiad, dan melatih sebuah model untuk identifikasi translator dari sebuah baris teks."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fgZ9gjmPfSnK"
      },
      "source": [
        "## Pengaturan"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "baYFZMW_bJHh"
      },
      "outputs": [],
      "source": [
        "from __future__ import absolute_import, division, print_function, unicode_literals\n",
        "\n",
        "try:\n",
        "  # %tensorflow_version only exists in Colab.\n",
        "  %tensorflow_version 2.x\n",
        "except Exception:\n",
        "  pass\n",
        "import tensorflow as tf\n",
        "\n",
        "import tensorflow_datasets as tfds\n",
        "import os"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YWVWjyIkffau"
      },
      "source": [
        "Tiga translasi teks dilakukan oleh:\n",
        "\n",
        " - [William Cowper](https://en.wikipedia.org/wiki/William_Cowper) — [teks](https://storage.googleapis.com/download.tensorflow.org/data/illiad/cowper.txt)\n",
        "\n",
        " - [Edward, Earl of Derby](https://en.wikipedia.org/wiki/Edward_Smith-Stanley,_14th_Earl_of_Derby) — [teks](https://storage.googleapis.com/download.tensorflow.org/data/illiad/derby.txt)\n",
        "\n",
        "- [Samuel Butler](https://en.wikipedia.org/wiki/Samuel_Butler_%28novelist%29) — [teks](https://storage.googleapis.com/download.tensorflow.org/data/illiad/butler.txt)\n",
        "\n",
        "File teks yang digunakan dalam tutorial ini sudah mengalami beberapa tahap *preprocessing*, kebanyakan prosesnya adalah menghilangkan beberapa bagian — header dan footer dari dokumen, jumlah baris, judul bab. Unduh file ringan ini di lokal."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "4YlKQthEYlFw"
      },
      "outputs": [],
      "source": [
        "DIRECTORY_URL = 'https://storage.googleapis.com/download.tensorflow.org/data/illiad/'\n",
        "FILE_NAMES = ['cowper.txt', 'derby.txt', 'butler.txt']\n",
        "\n",
        "for name in FILE_NAMES:\n",
        "  text_dir = tf.keras.utils.get_file(name, origin=DIRECTORY_URL+name)\n",
        "  \n",
        "parent_dir = os.path.dirname(text_dir)\n",
        "\n",
        "parent_dir"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "q3sDy6nuXoNp"
      },
      "source": [
        "## Memuat teks menjadi dataset\n",
        "\n",
        "Iterasi file, muat setiap file menjadi datasetnya masing-masing.\n",
        "\n",
        "Setiap contoh perlu diberi label, gunakan `tf.data.Dataset.map` untuk menggunakan fungsi pemberi label pada setiap contoh. Hal ini akan melakukan iterasi pada setiap contoh dalam dataset, dan mengembalikan pasangan (`example, label`)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "K0BjCOpOh7Ch"
      },
      "outputs": [],
      "source": [
        "def labeler(example, index):\n",
        "  return example, tf.cast(index, tf.int64)  \n",
        "\n",
        "labeled_data_sets = []\n",
        "\n",
        "for i, file_name in enumerate(FILE_NAMES):\n",
        "  lines_dataset = tf.data.TextLineDataset(os.path.join(parent_dir, file_name))\n",
        "  labeled_dataset = lines_dataset.map(lambda ex: labeler(ex, i))\n",
        "  labeled_data_sets.append(labeled_dataset)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "M8PHK5J_cXE5"
      },
      "source": [
        "Gabungkan dataset yang sudah diberikan label menjadi sebuah dataset, kemudian lakukan *shuffle* terhadap dataset tersebut."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6jAeYkTIi9-2"
      },
      "outputs": [],
      "source": [
        "BUFFER_SIZE = 50000\n",
        "BATCH_SIZE = 64\n",
        "TAKE_SIZE = 5000"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Qd544E-Sh63L"
      },
      "outputs": [],
      "source": [
        "all_labeled_data = labeled_data_sets[0]\n",
        "for labeled_dataset in labeled_data_sets[1:]:\n",
        "  all_labeled_data = all_labeled_data.concatenate(labeled_dataset)\n",
        "  \n",
        "all_labeled_data = all_labeled_data.shuffle(\n",
        "    BUFFER_SIZE, reshuffle_each_iteration=False)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "r4JEHrJXeG5k"
      },
      "source": [
        "Anda dapat menggunakan `tf.data.Dataset.take` dan `print` untuk melihat seperti apa bentuk dari `(example, label)`. Properti `numpy` menunjukkan nilai dari masing-masing Tensor."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "gywKlN0xh6u5"
      },
      "outputs": [],
      "source": [
        "for ex in all_labeled_data.take(5):\n",
        "  print(ex)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5rrpU2_sfDh0"
      },
      "source": [
        "## Melakukan enkode baris teks sebagai angka\n",
        "\n",
        "Model *machine learning* bekerja dengan angka, bukan kata-kata, sehingga nilai dari string harus dikonversi terlebih dahulu menjadi angka. Untuk melakukan hal tersebut, ubah kata unik menjadi bilangan integer yang unik.\n",
        "\n",
        "### Membangun kosa kata\n",
        "\n",
        "Pertama-tama, buat sebuah kosa kata dengan melakukan tokenisasi dari teks menjadi sebuah koleksi kata-kata unik. Terdapat beberapa cara untuk melakukan hal ini baik di TensorFlow maupun Python. Untuk tutorial ini:\n",
        "\n",
        "1. Iterasi setiap nilai `numpy` dari contoh. \n",
        "2. Gunakan `tfds.features.text.Tokenizer` untuk memisahkannya menjadi token.\n",
        "3. Kumpulkan token-token tersebut menjadi sebuah Python set, untuk menghilangkan duplikat.\n",
        "4. Peroleh ukuran dari kosa kata yang akan digunakan selanjutnya."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "YkHtbGnDh6mg"
      },
      "outputs": [],
      "source": [
        "tokenizer = tfds.features.text.Tokenizer()\n",
        "\n",
        "vocabulary_set = set()\n",
        "for text_tensor, _ in all_labeled_data:\n",
        "  some_tokens = tokenizer.tokenize(text_tensor.numpy())\n",
        "  vocabulary_set.update(some_tokens)\n",
        "\n",
        "vocab_size = len(vocabulary_set)\n",
        "vocab_size"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0W35VJqAh9zs"
      },
      "source": [
        "### Proses enkode contoh\n",
        "\n",
        "Buat sebuah enkoder dengan menggunakan `vocabulary_set` kepada `tfds.features.text.TokenTextEncoder`. *Method* dari enkoder `encode`memerlukan string dan mengembalikan list bilangan integer."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "gkxJIVAth6j0"
      },
      "outputs": [],
      "source": [
        "encoder = tfds.features.text.TokenTextEncoder(vocabulary_set)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v6S5Qyabi-vo"
      },
      "source": [
        "Anda dapat mencobanya pada satu baris untuk melihat bagaimana bentuk dari outputnya."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "jgxPZaxUuTbk"
      },
      "outputs": [],
      "source": [
        "example_text = next(iter(all_labeled_data))[0].numpy()\n",
        "print(example_text)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "XoVpKR3qj5yb"
      },
      "outputs": [],
      "source": [
        "encoded_example = encoder.encode(example_text)\n",
        "print(encoded_example)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "p9qHM0v8k_Mg"
      },
      "source": [
        "Sekarang gunakan enkoder tersebut pada dataset dengan cara membungkusnya dalam `tf.py_function` dan gunakan hasilnya pada *method* dataset `map`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "HcIQ7LOTh6eT"
      },
      "outputs": [],
      "source": [
        "def encode(text_tensor, label):\n",
        "  encoded_text = encoder.encode(text_tensor.numpy())\n",
        "  return encoded_text, label\n",
        "\n",
        "def encode_map_fn(text, label):\n",
        "  return tf.py_function(encode, inp=[text, label], Tout=(tf.int64, tf.int64))\n",
        "\n",
        "all_encoded_data = all_labeled_data.map(encode_map_fn)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_YZToSXSm0qr"
      },
      "source": [
        "## Bagi dataset menjadi batch tes dan train\n",
        "\n",
        "Gunakan `tf.data.Dataset.take` dan `tf.data.Dataset.skip` untuk membuat dataset tes berukuran kecil dan set training berukuran lebih besar.\n",
        "\n",
        "Sebelum digunakan pada model, perlu dibuat batch untuk dataset. Biasanya, data-data dalam satu batch harus memiliki bentuk dan ukuran yang sama. Akan tetapi, data-data dalam dataset ini tidak memiliki ukuran yang sama — setiap baris dari teks memiliki jumlah kata yang berbeda. Oleh karena itu, gunakan `tf.data.Dataset.padded_batch` (daripada `batch`) untuk membuat setiap data memiliki ukuran yang sama."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "r-rmbijQh6bf"
      },
      "outputs": [],
      "source": [
        "train_data = all_encoded_data.skip(TAKE_SIZE).shuffle(BUFFER_SIZE)\n",
        "train_data = train_data.padded_batch(BATCH_SIZE, padded_shapes=([-1],[]))\n",
        "\n",
        "test_data = all_encoded_data.take(TAKE_SIZE)\n",
        "test_data = test_data.padded_batch(BATCH_SIZE, padded_shapes=([-1],[]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Xdz7SVwmqi1l"
      },
      "source": [
        "Sekarang, `test_data` dan `train_data` bukan merupakan koleksi dari pasangan (`example, label`), tetapi koleksi dari batch. Setiap batch adalah pasangan dari (*beberapa data*, *beberapa label*) yang direpresentasikan sebagai array.\n",
        "\n",
        "Sebagai ilustrasi:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kMslWfuwoqpB"
      },
      "outputs": [],
      "source": [
        "sample_text, sample_labels = next(iter(test_data))\n",
        "\n",
        "sample_text[0], sample_labels[0]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UI4I6_Sa0vWu"
      },
      "source": [
        "Karena kita telah menggunakan sebuah *token encoding* yang baru (nilai nol digunakan untuk *padding*), jumlah kosa kata bertambah satu."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "IlD1Lli91vuc"
      },
      "outputs": [],
      "source": [
        "vocab_size += 1"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "K8SUhGFNsmRi"
      },
      "source": [
        "## Membangun model"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QJgI1pow2YR9"
      },
      "outputs": [],
      "source": [
        "model = tf.keras.Sequential()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wi0iiKLTKdoF"
      },
      "source": [
        "Layer pertama mengkonversi representasi integer menjadi *dense vector embeddings*. Lihat [tutorial *word embeddings*](../text/word_embeddings.ipynb) untuk detail lebih lanjut. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "DR6-ctbY638P"
      },
      "outputs": [],
      "source": [
        "model.add(tf.keras.layers.Embedding(vocab_size, 64))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_8OJOPohKh1q"
      },
      "source": [
        "Layer selanjutnya adalah layer [*Long Short-Term Memory*](http://colah.github.io/posts/2015-08-Understanding-LSTMs/), yang dapat membuat model memahami hubungan antara kata-kata. Sebuah wrapper dua arah dalam LSTM membantu model untuk mempelajari hubungan antara titik data dengan titik data lain yang ada setelah dan sebelumnya."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "x6rnq6DN_WUs"
      },
      "outputs": [],
      "source": [
        "model.add(tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(64)))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cdffbMr5LF1g"
      },
      "source": [
        "Kita akhirnya memiliki sebuah series dari satu atau lebih *densely connected layer*, dengan layer terakhir sebagai output layer. Output layer menghasilkan probabilitas dari masing-masing label. Label dengan probabilitas tertinggi merupakan prediksi dari model."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QTEaNSnLCsv5"
      },
      "outputs": [],
      "source": [
        "# Satu atau lebih dense layer.\n",
        "# Edit list pada baris `for` untuk bereksperimen dengan ukuran layer\n",
        "for units in [64, 64]:\n",
        "  model.add(tf.keras.layers.Dense(units, activation='relu'))\n",
        "\n",
        "# layer output. Argumen pertama adalah jumlah label.\n",
        "model.add(tf.keras.layers.Dense(3, activation='softmax'))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zLHPU8q5DLi_"
      },
      "source": [
        "Akhirnya, kita lakukan kompilasi terhadap model. Untuk model dengan kategorisasi softmax, gunakan `sparse_categorical_crossentropy` pada *loss function*. Anda dapat mencoba optimizer yang lainnya, tetapi `adam` adalah optimizer yang paling umum digunaknan."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "pkTBUVO4h6Y5"
      },
      "outputs": [],
      "source": [
        "model.compile(optimizer='adam',\n",
        "              loss='sparse_categorical_crossentropy',\n",
        "              metrics=['accuracy'])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DM-HLo5NDhql"
      },
      "source": [
        "## Latih model\n",
        "\n",
        "Model yang dilatih menggunakan data ini menghasilkan hasil yang cukup baik (sekitar 83%)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "aLtO33tNh6V8"
      },
      "outputs": [],
      "source": [
        "model.fit(train_data, epochs=3, validation_data=test_data)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "KTPCYf_Jh6TH"
      },
      "outputs": [],
      "source": [
        "eval_loss, eval_acc = model.evaluate(test_data)\n",
        "\n",
        "print('\\nEval loss: {:.3f}, Eval accuracy: {:.3f}'.format(eval_loss, eval_acc))"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "text.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
